package model.components.networks.virtual;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;

import model.components.links.comparator.LinkNumberComparator;
import model.components.links.link.Link;
import model.components.links.link.VirtualLink;
import model.components.networks.Network;
import model.components.networks.NetworkGraph;
import model.components.nodes.comparator.NodeNumberComparator;
import model.components.nodes.node.Node;
import model.components.nodes.node.sdn.SdnNode;
import model.components.nodes.node.virtual.VirtualMachine;
import model.components.nodes.node.virtual.VirtualNode;
import edu.uci.ics.jung.graph.Graph;

public class VirtualNetwork extends Network
{	
	private int startingDate;
	public int getStartingDate(){ return startingDate; }
	public void setStartingDate( int startingDate ){ this.startingDate = startingDate; }
	
	private int endingDate;
	public int getEndingDate(){ return endingDate; }
	public void setEndingDate( int endingDate ){ this.endingDate = endingDate; }
	
	private String softwareNetworkName = "";
	public String getSdnNetworkName(){ return softwareNetworkName; }
	public void setSdnNetworkName( String softwareNetworkName ){ this.softwareNetworkName = softwareNetworkName; }
	
	private List< VirtualNetwork > virtualSubnetworks;
	public List< VirtualNetwork > getVirtualSubnetworks(){ return virtualSubnetworks; }
	public void setVirtualSubnetworks( List< VirtualNetwork > virtualSubnetworks ){ this.virtualSubnetworks = virtualSubnetworks; }
	
	private LinkedHashMap< VirtualNode, SdnNode > virtualNodesMapping;
	public LinkedHashMap< VirtualNode, SdnNode > getNodesMapping(){ return virtualNodesMapping; }
	public void setVirtualNodesMapping( LinkedHashMap< VirtualNode, SdnNode > virtualNodesMapping ){ this.virtualNodesMapping = virtualNodesMapping; }
	
	private int virtualLinksMapping[][][][];
	public int[][][][] getLinksMapping(){ return virtualLinksMapping; }
	public void setLinksMapping( int virtualLinksMapping[][][][] ){ this.virtualLinksMapping = virtualLinksMapping; }
	
	private boolean denied;
	public boolean isDenied(){ return denied; }
	public void setDenied( boolean denied ){ this.denied = denied; }
	
	private int networkCost;
	public int getNetworkCost(){ return networkCost; }
	public void setNetworkCost( int networkCost ){ this.networkCost = networkCost; }
	
	public VirtualNetwork( String namePrefix, int number )
    {
    	super( namePrefix, number, new NetworkGraph() );
    }
	
	public VirtualNetwork( String namePrefix, int number, int startingDate, int endingDate )
    {
    	super( namePrefix, number, new NetworkGraph() );
    	
    	this.setStartingDate( startingDate );
		this.setEndingDate( endingDate );
    }
	
	public VirtualNetwork( String namePrefix, int number, Graph< Node, Link > graph, int startingDate, int endingDate )
    {
    	super( namePrefix, number, graph );
    	
    	this.setStartingDate( startingDate );
		this.setEndingDate( endingDate );
    }
	
	public VirtualNetwork getCopy() 
	{
		VirtualNetwork virtualNetwork = new VirtualNetwork( this.getNamePrefix(), this.getNumber(), ( (NetworkGraph) this.getGraph() ).getCopy(), this.getStartingDate(), this.getEndingDate() );
		virtualNetwork.setState( this.getState() );
    	virtualNetwork.setChange( this.isChange() );
    	virtualNetwork.setTimeStamp( this.getTimeStamp() );
    	
    	return virtualNetwork;
    }
	
	public List< VirtualNode > getVirtualNodes()
	{
		List< VirtualNode > virtualNodes = new ArrayList< VirtualNode >();
		
		for( Node node: this.getNodes() )
			virtualNodes.add( ( VirtualNode )node );
		
		Collections.sort( virtualNodes, new NodeNumberComparator() );
		
		return virtualNodes;
	}
	
	public double[][] getNodesCapacities()
	{
		double nodesCapacities[][] = new double[ 3 ][ this.getNodes().size() ];

		for( int i = 0; i < this.getVirtualNodes().size(); i++ )
		{
			VirtualNode virtualNode = this.getVirtualNodes().get( i );

			nodesCapacities[ 0 ][ i ] = virtualNode.getCPU();
			nodesCapacities[ 1 ][ i ] = virtualNode.getRAM();
			
			if( virtualNode instanceof VirtualMachine )
				nodesCapacities[ 2 ][ i ] = virtualNode.getStorage();
		}
		
		return nodesCapacities;
	}
	
	public List< VirtualLink > getVirtualLinks()
    {
    	List< VirtualLink > links = new ArrayList< VirtualLink >();
		
		for( Link link: this.getLinks() )
			links.add( ( VirtualLink )link );
		
		Collections.sort( links, new LinkNumberComparator() );
    	
    	return links;
	}
	
	public double[][] getBandwidths()
	{
		double bandwidths[][] = new double[ this.getNodes().size() ][ this.getNodes().size() ];
		
		for( VirtualLink virtualLink: this.getVirtualLinks() )
		{
			bandwidths[ virtualLink.getFirstNode().getNumber()  ][ virtualLink.getSecondNode().getNumber() ] = virtualLink.getBW();
			bandwidths[ virtualLink.getSecondNode().getNumber() ][ virtualLink.getFirstNode().getNumber()  ] = virtualLink.getBW();
		}
		
		return bandwidths;
	}
	
}
